package com.qwc.blog.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.NumberUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qwc.blog.common.constant.CommonConstant;
import com.qwc.blog.entity.*;
import com.qwc.blog.entity.dto.ArticleDto;
import com.qwc.blog.entity.dto.ArticleRequestDto;
import com.qwc.blog.entity.dto.ArticleReturnDto;
import com.qwc.blog.entity.dto.BlogArticleDto;
import com.qwc.blog.entity.vo.ArticleWithTagVo;
import com.qwc.blog.mapper.*;
import com.qwc.blog.service.IArticleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 文章元信息表 服务实现类
 * </p>
 *
 * @author qwc
 * @since 2022-01-24
 */
@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> implements IArticleService {

    @Autowired
    private ClassifyMapper classifyMapper;

    @Autowired
    private ContentMapper contentMapper;

    @Autowired
    private TagMapper tagMapper;

    @Autowired
    private BlogLogMapper blogLogMapper;

    @Override
    public ArticleRequestDto<Article> pageList(ArticleRequestDto<Article> dto) {
        List<Integer> ids = new ArrayList<>();
        getClassifyIds(dto.getPid(), ids);
        ArticleRequestDto<Article> articleArticleRequestDto = baseMapper.selectPageDto(dto, ids);
        articleArticleRequestDto.setRecords(articleArticleRequestDto
                .getRecords()
                .stream()
                .collect(Collectors.collectingAndThen(
                        Collectors.toCollection(()->
                                new TreeSet<Article>(Comparator.comparing(p -> p.getArticleId()))), ArrayList::new)
                )
        );
        return articleArticleRequestDto;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveArticleAndContent(ArticleDto dto) {
//        保存文章信息
        Article article = new Article();
        BeanUtil.copyProperties(dto, article);
        int insert = baseMapper.insert(article);
//        保存文章内容
        Content content = new Content();
        content.setContent(dto.getContent());
        content.setArticleId(article.getArticleId());
        insert += contentMapper.insert(content);
        insert += insertClassifyAndTag(dto, article);
        if (CommonConstant.ABLE.equals(dto.getStatus())) {
            logBlog(dto.getStatus(),dto.getTitle());

        }
        return insert > 0;
    }

    @Override
    public ArticleReturnDto getByArticleId(Integer id) {
        Article article = baseMapper.selectById(id);
        ArticleReturnDto articleDto = new ArticleReturnDto();
        BeanUtil.copyProperties(article, articleDto);
        List<Integer> classifyIds = classifyMapper.selectByArticleId(article.getArticleId());
        articleDto.setClassifyIds(classifyIds);
        List<Integer> tagIds = tagMapper.selectByArticleId(article.getArticleId());
        articleDto.setTagIds(tagIds);
        Content content = contentMapper.selectOne(Wrappers.<Content>lambdaQuery().eq(Content::getArticleId, article.getArticleId()));
        articleDto.setContent(content.getContent());
        return articleDto;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateByArticleId(ArticleDto dto) {
        Article article = new Article();
        BeanUtil.copyProperties(dto, article);
        Article article1 = baseMapper.selectById(dto.getArticleId());
        if (!article1.getStatus().equals(article.getStatus())) {
            logBlog(article.getStatus(),article.getTitle());
        }
        int i = baseMapper.updateById(article);
        i += contentMapper.update(null, Wrappers.<Content>lambdaUpdate()
                .set(Content::getContent, dto.getContent())
                .eq(Content::getArticleId, dto.getArticleId()));
        baseMapper.deleteClassifyByArticleId(dto.getArticleId());
        baseMapper.deleteTagByArticleId(dto.getArticleId());
        i += insertClassifyAndTag(dto, article);
        return i > 0;
    }

    @Override
    public boolean removeAllByIds(List<Integer> asList) {
        int i = baseMapper.deleteBatchIds(asList);
        i += contentMapper.delete(Wrappers.<Content>lambdaQuery().in(Content::getArticleId, asList));
        i += baseMapper.deleteArticleClassify(asList);
        i += baseMapper.deleteArticleTag(asList);
        return i > 0;
    }

    @Override
    @Cacheable(cacheNames = "article")
    public List<Article> listFromCache() {
        return baseMapper.selectList(Wrappers.<Article>lambdaQuery()
                .eq(Article::getStatus,CommonConstant.ABLE)
                .last("ORDER BY RAND() LIMIT 5"));
    }

    @Override
    public Page<ArticleWithTagVo> pageWithTag(BlogArticleDto dto) {
        if (CommonConstant.ROOT.equals(dto.getClassifyId())) {
            return baseMapper.pageWithTag(Page.of(dto.getCurrent(),CommonConstant.PAGE_SIZE),dto);
        }
        List<Integer> ids = new ArrayList<>();
        getClassifyIds(dto.getClassifyId(), ids);
        Page<ArticleWithTagVo> articleWithTagVoPage = baseMapper.pageWithTagByClassifyId(Page.of(dto.getCurrent(), CommonConstant.PAGE_SIZE), ids);
        articleWithTagVoPage.setRecords(articleWithTagVoPage.getRecords()
                .stream().collect(Collectors.collectingAndThen(
                Collectors.toCollection(()->
                        new TreeSet<ArticleWithTagVo>(Comparator.comparing(p -> p.getArticleId()))), ArrayList::new)
        )
        );
        return articleWithTagVoPage;
    }

    private void checkTagsExist(List<String> tagIds) {
        List<String> collect = tagIds.stream().filter(id -> !NumberUtil.isNumber(id)).collect(Collectors.toList());
        for (String s : collect) {
            Tag tag = new Tag();
            tag.setName(s);
            tagMapper.insert(tag);
            tagIds.add(tag.getTagId().toString());
        }
    }

    private void getClassifyIds(Integer pid, List<Integer> ids) {
        if (Objects.nonNull(pid)) {
            ids.add(pid);
        }
        List<Classify> classifies = classifyMapper.selectList(Wrappers.<Classify>lambdaQuery()
                .eq(Classify::getPid, pid)
                .eq(Classify::getStatus, CommonConstant.ABLE));
        List<Integer> classifyId = classifies.stream().map(Classify::getClassifyId).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(classifyId)) {
            for (Integer integer : classifyId) {
                getClassifyIds(integer, ids);
            }
        }
    }

    private int insertClassifyAndTag(ArticleDto dto, Article article) {
//        保存文章分类关联
        int insert = baseMapper.insertArticleClassify(article.getArticleId(), dto.getClassifyIds());
//        保存文章标签
        checkTagsExist(dto.getTagIds());
        if (CollUtil.isNotEmpty((dto.getTagIds()))) {
            insert += baseMapper.insertArticleTag(article.getArticleId(), dto.getTagIds()
                    .stream()
                    .filter(NumberUtil::isNumber)
                    .map(Integer::valueOf)
                    .collect(Collectors.toList()));
        }
        return insert;
    }

    private void logBlog(String status, String title) {
        BlogLog blogLog = new BlogLog();
        blogLog.setBlogEvent(status);
        blogLog.setBlogEventDesc(title);
        blogLogMapper.insert(blogLog);
    }
}
